'use strict'
/*filter也是一个常用的操作，它用于把Array的某些元素过滤掉，然后返回剩下的元素。
和map()类似，Array的filter()也接收一个函数，和map()不同的是，filter()把传入的函数依次作用于每个元素，然后根据返回值true或false决定保留还是丢弃该元素。
*/
//删掉偶数，保留奇数
var arr =[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var r = arr.filter(function(x){
    return x% 2 !== 0;
});
console.log(r);
//把Array中的空字符串去掉
var arr = ['A', '', 'B', null, undefined, 'C', '   '];
var rr =arr.filter(function(s){
    return s && s.trim();
});
console.log(rr);
/*filter()接收的回调函数，其实可以有多个参数。通常我们仅使用第一个参数，表示Array的某个元素。回调函数还可以接收另外两个参数，表示元素的位置和数组本身：*/
var arr = ['a','b','c'];
var rrr =arr.filter(function(element,index,self){
    console.log(element);
    console.log(index);
    console.log(self);
    return true;
});

/*sort 排序算法
sort()方法会直接对Array进行修改，它返回的结果仍然是当前Array.
sort()也是一个高级函数，可以接收一个比较函数来实现自定义的排序*/
var arr = [41,56,16,41,63,4];
arr.sort(function(x,y){
    if(x<y){
        return -1;
    }if(x>y){
        return 1;
    }
    return 0;
});
console.log(arr);

var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(v,h){
    if(v<h){
        return 1;
    }if(v>h){
        return -1;
    }
    return 0;
});
console.log(arr);

var arr =['gfg','FGi','fgUY'];
arr.sort(function(s1,s2){
    var x1 = s1.toUpperCase();
    var x2 = s2.toUpperCase();
    if(x1<x2){
        return -1;
    }if(x1>x2){
        return 1;
    }
    return 0;
});
console.log(arr);

/*
 闭包
函数做为返回值
高阶函数除了可以接收函数做为参数外，还可以把函数做为结果值返回
*/
//普通求和
function sum(arr1){
    return arr1.reduce(function(x,y){
        return x + y;
    });
}
console.log(sum([1,2,3,4]));

//但是如果不需要立刻求和，而是在后面的代码中，根据需要再计算怎么办？可以不返回求和的结果，返回求和的函数
function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    };
}
//var f = lazy_sum([1, 2, 3, 4, 5]);  //function sum()

var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
console.log(f1 === f2); // false
//console.log(f); //15 
/*注意到返回的函数在其定义内部引用了局部变量arr，所以，当一个函数返回了一个函数后，其内部的局部变量还被新函数引用，所以，闭包用起来简单，实现起来可不容易。
返回函数并没有立刻执行，而是直到调用了f()才执行
*/
function count(){
    var arr = [];
    for(var i=1;i<=3;i++){
        arr.push(function(){
            return i*i;
        });
    }
    return arr;
}
var results =count();

var f2 = results[0];
var f3 = results[1];
var f4 = results[2];

console.log(f2());
console.log(f3());
console.log(f4());
//全部都是16， 原因在于返回的函数引用了变量i，但它并非立刻执行。等到3个函数都返回时，它们所引用的变量i已经变成了4，因此最终结果为16。

/*返回闭包时牢记的一点就是：返回函数不要引用任何循环变量，或者后续会发生变化的变量。
如果一定要引用循环变量怎么办？方法是再创建一个函数，用该函数的参数绑定循环变量当前的值，无论该循环变量后续如何更改，已绑定到函数参数的值不变
*/
//创建一个计数器：
function count1(){
    let arr = [];
    for(let i =1;i<=3;i++){
        arr.push((function(n){
            return function(){
                return n * n;
            };
        })(i));
    }
    return arr;
}

var results1 =count1();

var f22 = results[0];
var f33 = results[1];
var f44 = results[2];

console.log(f22());//1
console.log(f33());//4
console.log(f44());//9

/*闭包还可以把多参数的函数变成单参数的函数。例如，要计算xy可以用Math.pow(x, y)函数，
不过考虑到经常计算x2或x3，我们可以利用闭包创建新的函数pow2和pow3：*/
function make_pow(n) {
    return function (x) {
        return Math.pow(x, n);
    }
}

var pow2 = make_pow(2);
var pow3 = make_pow(3);

console.log(pow2(5));  //25
console.log(pow3(7)); //343

/*箭头函数相当于匿名函数，并且简化了函数定义。箭头函数有两种格式，
一种像上面的，只包含一个表达式，连{ ... }和return都省略掉了。
还有一种可以包含多条语句，这时候就不能省略{ ... }和return：
*/